package com.carl.mall.product.service.impl;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.carl.common.constant.ProductConstant;
import com.carl.common.dto.SkuHasStockDto;
import com.carl.common.dto.SkuReductionDTO;
import com.carl.common.dto.SpuBoundsDTO;
import com.carl.common.dto.es.SkuESModel;
import com.carl.common.utils.R;
import com.carl.common.utils.splitUrl;
import com.carl.mall.product.convert.EntityToVoConvert;
import com.carl.mall.product.dao.AttrAttrgroupRelationDao;
import com.carl.mall.product.dao.SkuInfoDao;
import com.carl.mall.product.entity.*;
import com.carl.mall.product.feign.CouponFeignService;
import com.carl.mall.product.feign.ElasticSaveService;
import com.carl.mall.product.feign.WareFeignService;
import com.carl.mall.product.service.*;
import com.carl.mall.product.vo.skuvo.*;
import com.google.common.base.Preconditions;
import com.mysql.cj.x.protobuf.MysqlxDatatypes;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.carl.common.utils.PageUtils;
import com.carl.common.utils.Query;

import com.carl.mall.product.dao.SpuInfoDao;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;


@Service("spuInfoService")
public class SpuInfoServiceImpl extends ServiceImpl<SpuInfoDao, SpuInfoEntity> implements SpuInfoService {


    @Autowired
    private SpuInfoDescService spuInfoDescService;

    @Autowired
    private SpuImagesService spuImagesService;

    @Autowired
    private AttrService attrService;

    @Autowired
    private AttrAttrgroupRelationDao attrAttrgroupRelationDao;

    @Autowired
    private ProductAttrValueService productAttrValueService;

    @Autowired
    private SkuInfoService skuInfoService;

    @Autowired
    private SkuSaleAttrValueService skuSaleAttrValueService;

    @Autowired
    private SkuImagesService skuImagesService;

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private BrandService brandService;

    //远程调用接口
    @Autowired
    CouponFeignService couponFeignService;

    //远程调用接口
    @Autowired
    WareFeignService wareFeignService;

    //远程调用接口
    @Autowired
    private ElasticSaveService elasticSaveService;



    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                new QueryWrapper<SpuInfoEntity>()
        );

        return new PageUtils(page);
    }


    /**
     * 保存商品发布信息
     * @param skuInfoVO
     */
    @Transactional
    @Override
    public void saveSpuInfo(SpuInfoVO skuInfoVO) {
            //1.保存spu的基本信息 pms_spu_info
        SpuInfoEntity spuInfoEntity = EntityToVoConvert.INSTANCE.spuInfoVOTOSpuInfoEntity(skuInfoVO);
        spuInfoEntity.setCreateTime(new Date());
        spuInfoEntity.setUpdateTime(new Date());
        this.save(spuInfoEntity);
           //2.保存spu的详情信息 pms_spu_info_desc
        List<String> decript = skuInfoVO.getDecript();
        SpuInfoDescEntity spuInfoDescEntity = new SpuInfoDescEntity();
        spuInfoDescEntity.setSpuId(spuInfoEntity.getId());
        spuInfoDescEntity.setDecript(String.join(",",decript));
        spuInfoDescService.save(spuInfoDescEntity);
          //3.保存商品的图集信息 pms_spu_images
        List<String> images = skuInfoVO.getImages();
        List<SpuImagesEntity> list = images.stream().map((e) -> {
            SpuImagesEntity spuImagesEntity = new SpuImagesEntity();
            spuImagesEntity.setSpuId(spuInfoEntity.getId());
            spuImagesEntity.setImgUrl(e);
            String imgName = new splitUrl().urlSplit(e);
            spuImagesEntity.setImgName(imgName);
            return spuImagesEntity;
        }).collect(Collectors.toList());
        spuImagesService.saveBatch(list);
        //4.保存规格参数 pms_product_attr_value
        List<BaseAttrs> baseAttrs = skuInfoVO.getBaseAttrs();
        List<ProductAttrValueEntity> productAttrValueEntities = baseAttrs.stream().map((baseAttr) -> {
            ProductAttrValueEntity productAttrValueEntity = new ProductAttrValueEntity();
            productAttrValueEntity.setSpuId(spuInfoEntity.getId());
            productAttrValueEntity.setAttrId(baseAttr.getAttrId());
            AttrEntity attrEntity = attrService.getById(baseAttr.getAttrId());
            productAttrValueEntity.setAttrName(attrEntity.getAttrName());  //前端自定义属性值的时候容易产生空指针异常
            productAttrValueEntity.setAttrValue(baseAttr.getAttrValues());
            productAttrValueEntity.setQuickShow(baseAttr.getShowDesc());
            AttrAttrgroupRelationEntity relationEntity = attrAttrgroupRelationDao
                    .selectOne(new QueryWrapper<AttrAttrgroupRelationEntity>()
                            .eq("attr_id", baseAttr.getAttrId()));
            productAttrValueEntity.setAttrSort(relationEntity.getAttrSort());
            return productAttrValueEntity;
        }).collect(Collectors.toList());
        productAttrValueService.saveBatch(productAttrValueEntities);
        //5.保存当前的spu对应的所有的sku（销售属性）的信息
                //5.1 保存sku的基本信息pms_sku_info
        List<Skus> skus = skuInfoVO.getSkus();
        if (!StringUtils.isEmpty(skus)){
            skus.forEach((sku)-> {
                SkuInfoEntity skuInfoEntity = EntityToVoConvert.INSTANCE.skusTOskuInfoEntity(sku);
                skuInfoEntity.setSpuId(spuInfoEntity.getId());
                skuInfoEntity.setCatalogId(spuInfoEntity.getCatalogId());
                skuInfoEntity.setBrandId(spuInfoEntity.getBrandId());
                skuInfoEntity.setSaleCount(0L);
                List<Images> images1 = sku.getImages();
                String defaultImage = "sku图片为空";
                for (Images images2 : images1) {
                    if (images2.getDefaultImg() == 1) {
                        defaultImage = images2.getImgUrl();
                    }
                }
                skuInfoEntity.setSkuDefaultImg(defaultImage);
                skuInfoService.save(skuInfoEntity);
                //5.2 保存sku销售属性信息pms_sku_sale_attr_value
                List<Attr> attrs = sku.getAttr();
                List<SkuSaleAttrValueEntity> skuSaleAttrValueEntities = attrs.stream().map((attr) -> {
                    SkuSaleAttrValueEntity skuSaleAttrValueEntity = EntityToVoConvert
                            .INSTANCE.attrsTOSkuSaleAttrValueEntity(attr);
                    skuSaleAttrValueEntity.setSkuId(skuInfoEntity.getSkuId());
                    return skuSaleAttrValueEntity;
                }).collect(Collectors.toList());
                skuSaleAttrValueService.saveBatch(skuSaleAttrValueEntities);
                //5.3 保存sku的图片信息 pms_sku_image
                List<SkuImagesEntity> skuImagesEntities = images1.stream().map((img) -> {
                    SkuImagesEntity skuImagesEntity = new SkuImagesEntity();
                    skuImagesEntity.setSkuId(skuInfoEntity.getSkuId());
                    skuImagesEntity.setImgUrl(img.getImgUrl());
                    skuImagesEntity.setDefaultImg(img.getDefaultImg());
                    return skuImagesEntity;
                }).filter((img) -> {
                    return img != null && img.getImgUrl() != null && !img.getImgUrl().isEmpty() && !img.getImgUrl().trim().isEmpty(); //将图片链接为空的过滤掉
                }).collect(Collectors.toList());
                skuImagesService.saveBatch(skuImagesEntities);
                //5.4 mall_sms服务中 保存满减信息sms_sku_full_reduction，折扣sms_sku_ladder，会员价sms_member_price
                SkuReductionDTO skuReductionDTO =null;
                if(sku.getMemberPrice() != null && !sku.getMemberPrice().isEmpty()) {
                    skuReductionDTO = EntityToVoConvert.INSTANCE.skuTOSkuReductionDTO(sku);
                    skuReductionDTO.setSkuId(skuInfoEntity.getSkuId());
                }
                R r =  couponFeignService.saveFullReductionInfo(skuReductionDTO);
                if (r.getCode() != 0){
                    log.error("调用Coupon服务处理满减、折扣、会员价操作失败...");
                }
            });
        }
             //6.保存积分信息（第一步中的）  mall_sms: sms_spu_bounds
        Bounds bounds = skuInfoVO.getBounds();
        SpuBoundsDTO spuBoundsDTO = new SpuBoundsDTO();
        spuBoundsDTO.setSpuId(spuInfoEntity.getId());
        spuBoundsDTO.setGrowBounds(bounds.getGrowBounds());
        spuBoundsDTO.setBuyBounds(bounds.getBuyBounds());
        R r = couponFeignService.saveBoundInfo(spuBoundsDTO);
        if (r.getCode() != 0){
            log.error("调用Coupon服务处理积分操作失败...");
        }
    }

    @Override
    public PageUtils queryPageByCondition(Map<String, Object> params) {
        QueryWrapper<SpuInfoEntity> wrapper = new QueryWrapper<>();
        String key = (String) params.get("key");
        if (!StringUtils.isEmpty(key)){
            wrapper.and((queryWrapper) ->{
                queryWrapper.eq("id",key).or().like("spu_name",key).or().like("spu_description",key);
            });
        }
        //status
        String status = ( String)params.get("status");
        if (!StringUtils.isEmpty(status) ){
            wrapper.eq("publish_status",status);
        }
        // catalogId
        String catalogId = ( String)params.get("catelogId");
        if (!StringUtils.isEmpty(catalogId)&&!"0".equalsIgnoreCase(catalogId)){
            wrapper.eq("catalog_id",catalogId);
        }
        //brandId
        String brandId = ( String)params.get("brandId");
        if (!StringUtils.isEmpty(brandId)&&!"0".equalsIgnoreCase(brandId)){
            wrapper.eq("brand_id",brandId);
        }
        IPage<SpuInfoEntity> page = this.page(
                new Query<SpuInfoEntity>().getPage(params),
                wrapper
        );

        List<SpuInfoVO> list = page.getRecords().stream().map((spuInfoEntity -> {
            Long catalogId1 = spuInfoEntity.getCatalogId();
            Long brandId1 = spuInfoEntity.getBrandId();
            String cateLogName = categoryService.getById(catalogId1).getName();
            String brandName = brandService.getById(brandId1).getName();
            SpuInfoVO spuInfoVO = EntityToVoConvert.INSTANCE.spuInfoEnToSpuInfoVo(spuInfoEntity);
            spuInfoVO.setBrandName(brandName);
            spuInfoVO.setCatalogName(cateLogName);
            return spuInfoVO;
        })).collect(Collectors.toList());

        IPage<SpuInfoVO> page1 = new Page<>();
        page1.setRecords(list);
        page1.setPages(page.getPages());
        page1.setCurrent(page.getCurrent());
        page1.setSize(page.getSize());
        page1.setTotal(page.getTotal());
        return new PageUtils(page1);




    }

    /**
     * 商品的上架功能
     * 传递过来一个spuID 需要根据spuID查询出需要存储在Es中的数据
     * 在把数据存到es中（调用mall-search中的接口），并把spu的状态修改为上架
     *
     * @param spuId
     */
    @Override
    public void upSpu(Long spuId) {
        // 1.根据spuId查询相关的信息 封装到SkuESModel对象中
        List<SkuESModel> skuEs  = new ArrayList<>();
        //根据spuId查询出sku的信息
        List<SkuInfoEntity> skuInfoEntities = skuInfoService.queryBySpuId(spuId);
        //根据spuId获取对应的规格参数信息
        List<SkuESModel.Attrs> attrsList = getAttrsList(spuId);
        //hasStock   -> 去库存系统中查 查一个就行，根据skuId获取对应的库存信息
        //先获取spu下的skuId列表
        List<Long> skuIds = skuInfoEntities.stream().map(SkuInfoEntity::getSkuId).collect(Collectors.toList());
        Map<Long, Boolean> skusHasStock = getSkusHasStock(skuIds);
        List<SkuESModel> skuESModels = skuInfoEntities.stream().map((sku) -> {
            SkuESModel skuESModel = new SkuESModel();
            BeanUtils.copyProperties(sku,skuESModel);
            skuESModel.setSubTitle(sku.getSkuTitle());
            skuESModel.setSkuPrice(sku.getPrice());
            skuESModel.setSkuImg(sku.getSkuDefaultImg());
            //hasStock是否有库存
            if (skusHasStock == null){ //避免操作空指针 防止spu没有sku 忘了就看getSkusHasStock方法
                skuESModel.setHasStock(true);
            }else {
                skuESModel.setHasStock(skusHasStock.get(sku.getSkuId()));
            }
            //hotScore    -> 默认给0
            skuESModel.setHotScore(0L);
            //品牌名称和分类名称
            BrandEntity brandEntity = brandService.getById(sku.getBrandId());
            CategoryEntity categoryEntity = categoryService.getById(sku.getCatalogId());
            skuESModel.setBrandName(brandEntity.getName());
            skuESModel.setCatalogName(categoryEntity.getName());
            skuESModel.setBrandImg(brandEntity.getLogo());
            skuESModel.setAttrs(attrsList);
            return skuESModel;
        }).collect(Collectors.toList());
        //将skuEsModel中的数据存储到ES中
        R r = elasticSaveService.productStatusUp(skuESModels);
        //根据对应的状态更新商品的状态
        if (r.getCode() == 0){
            //远程调用成功 改变商品状态->新建->已上架
             baseMapper.updateSpuStatus(spuId, ProductConstant.ProductStatusEnum.SPU_UP.getCode());
        }



    }

    /**
     * 根据skuIds获取对应的库存状态
     */
    private Map<Long,Boolean> getSkusHasStock(List<Long> skuIds){
        List<SkuHasStockDto> stockDtos = null;
        if (StringUtils.isEmpty(skuIds)){
            return null;
        }
        try {
            stockDtos = wareFeignService.infoSkuId(skuIds);
            //把list转换成map key:skuId value:true/false
            Map<Long, Boolean> map = stockDtos.stream()
                    .collect(Collectors.toMap(SkuHasStockDto::getSkuId, SkuHasStockDto::getHasStock));
            return map;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }



    /**
     * 根据spuId获取对应的规格参数信息
     * @param spuId
     * @return
     */
    private List<SkuESModel.Attrs> getAttrsList(Long spuId) {
        //对应的规格参数，由于一个spu下有多个sku且这些sku的规格参数都一样，所以抽出来写，在循环里直接设置就行
        //1.在pms_product_attr_value这张表里通过spuId查询出规格参数列表
        List<ProductAttrValueEntity>  productAttrValueEntityList =
                productAttrValueService.queryProductAttrValueEntityBySpuId(spuId);
        //2.通过这里面查到的attr_id再去pms_attr这张表里查询该属性的search_type为1（是否需要检索[0-不需要，1-需要]）
        //2.1先把attr_id过滤出来
        List<Long> attrIdList = productAttrValueEntityList.stream()
                .map(ProductAttrValueEntity::getAttrId).collect(Collectors.toList());
        //2.2再去pms_attr查询出该属性的search_type为1（是否需要检索[0-不需要，1-需要]）
        //是把spu对应的attr_value放到SkuESModel.Attrs里
        List<Long> attrIds = attrService.selectSearchAttrIds(attrIdList);
        List<SkuESModel.Attrs> attrsList = productAttrValueEntityList.stream()
                .filter((item->{ //过滤可以检索的
                    return attrIds.contains(item.getAttrId());
                })).map((item) -> {
            SkuESModel.Attrs attrs = new SkuESModel.Attrs();
            BeanUtils.copyProperties(item, attrs);
            return attrs;
        }).collect(Collectors.toList());
        return attrsList;
    }


}